package com.cn.http.abstracts;

import com.cn.enums.HttpMethodEnum;
import com.cn.enums.TypeBodyEnum;
import com.cn.http.HttpConfig;
import com.cn.http.HttpParam;
import com.cn.http.HttpRequest;
import com.cn.http.HttpResponse;
import com.cn.http.impl.Http;
import com.cn.utils.MapUtils;
import com.cn.utils.StrUtils;
import lombok.Getter;
import lombok.Setter;

import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

/**
 * &#064;Time 2024 八月 星期日 17:04
 *
 * @author ShangGuan
 */
public abstract class AbstractHttpRequest implements HttpRequest {
    private final Http http;

    @Getter
    @Setter
    private HttpURLConnection connection;

    private HttpParam httpParam;
    /**
     * 配置高于一切请求头
     */
    @Getter
    private HttpConfig httpConfig;

    private boolean isFileUpload;

    public AbstractHttpRequest(Http http) {
        this.http = http;
        this.isFileUpload = false;
    }


    @Override
    public void enableFileUpload() {
        isFileUpload = true;
    }

    @Override
    public HttpRequest setRequestParams(HttpParam httpParam) {
        this.httpParam = httpParam;
        return this;
    }

    @Override
    public HttpRequest setRequestMethod(HttpMethodEnum method) {
        http.setMethod(method);
        return this;
    }

    @Override
    public void setConfig(HttpConfig httpConfig) {
        this.httpConfig = httpConfig;
    }

    @Override
    public HttpResponse post() throws IOException {
        setRequestMethod(HttpMethodEnum.POST);
        return execute();
    }

    @Override
    public HttpResponse get() throws IOException {
        setRequestMethod(HttpMethodEnum.GET);
        return execute();
    }

    @Override
    public HttpResponse put() throws IOException {
        setRequestMethod(HttpMethodEnum.PUT);
        return execute();
    }

    @Override
    public HttpResponse delete() throws IOException {
        setRequestMethod(HttpMethodEnum.DELETE);
        return execute();
    }

    private URL constructRequestParam() throws MalformedURLException {
        URL url = http.getUrl();
        if (StrUtils.isEmpty(httpParam.getUrlForm())) {
            return http.getUrl();
        }
        StringBuilder stringBuilder = new StringBuilder(url.getProtocol() + "://" + url.getHost() + ":" + url.getPort());
        if (StrUtils.isEmpty(url.getPath())) {
            stringBuilder.append("?").append(httpParam.getUrlForm());
        } else {
            stringBuilder.append("/").append(url.getPath()).append("?").append(httpParam.getUrlForm());
        }
        this.http.setUrl(new URL(stringBuilder.toString()));
        return http.getUrl();
    }

    protected HttpURLConnection constructConnection() throws IOException {
        URL url = constructRequestParam();
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        connection = urlConnection;
        urlConnection.setRequestMethod(http.getMethod().name());
        //设置请求头
        if (!MapUtils.isEmpty(new HashMap<>(http.getHeaders()))) {
            http.getHeaders().keySet().forEach(header ->
                    urlConnection.addRequestProperty(header, http.getHeaders().get(header)));
        }
        //配置
        config();
        if (http.getMethod().equals(HttpMethodEnum.POST)) {
            setBody();
        }
        return urlConnection;
    }

    /**
     * 设定主体
     */
    private void setBody() {
        //文件上传
        connection.setDoOutput(true);
        //文件上传
        try (OutputStream outputStream = connection.getOutputStream()) {
            if (isFileUpload) {
                TypeBodyEnum type = httpParam.getType();
                if (type == null) throw new RuntimeException("content-type is null");
                type.write(outputStream, httpParam.getBody(), httpParam.getFileUpload());
            } else {
                if (httpParam.getBody() != null) {
                    //需要实现的
                    outputStream.write(httpParam.getBody().getBytes());
                }
            }
            outputStream.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    protected abstract void config();


    @Override
    public abstract HttpResponse execute() throws IOException;
}
